package org.dftproject.genesis.ui.views;

import java.net.URI;
import java.net.URL;
import java.util.Iterator;

import org.dftproject.genesis.core.data.flow.Collector;
import org.dftproject.genesis.core.data.flow.DataBroker;
import org.dftproject.genesis.core.data.flow.ICollectorListener;
import org.dftproject.genesis.data.genealogy.IPerson;
import org.dftproject.genesis.ui.Activator;
import org.dftproject.genesis.ui.editors.BrowserEditor;
import org.dftproject.genesis.ui.editors.BrowserEditorInput;
import org.dftproject.genesis.ui.widgets.PersonHyperlink;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.HyperlinkGroup;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.part.ViewPart;

public class RelatedItemsView extends ViewPart implements ISelectionListener {

	public static final String ID = RelatedItemsView.class.getName();

	private HyperlinkGroup linkGroup;
	private Composite relatedObjectsComposite;

	private Collector<Object> collector;

	@Override
	public void createPartControl(Composite parent) {
		parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
		parent.setBackgroundMode(SWT.INHERIT_DEFAULT);

		GridLayout layout = new GridLayout();
		layout.marginTop = layout.marginRight = layout.marginBottom = layout.marginLeft = layout.marginWidth = layout.marginHeight = 4;
		parent.setLayout(layout);

		Label label = new Label(parent, SWT.NONE);
		label.setText("See also:");

		linkGroup = new HyperlinkGroup(parent.getDisplay());

		relatedObjectsComposite = new Composite(parent, SWT.NONE);
		layout = new GridLayout();
		layout.marginTop = layout.marginRight = layout.marginBottom = layout.marginLeft = layout.marginWidth = layout.marginHeight = 0;
		layout.verticalSpacing = 4;
		relatedObjectsComposite.setLayout(layout);
		relatedObjectsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		ISelectionService s = getSite().getWorkbenchWindow().getSelectionService();
		s.addSelectionListener(this);
	}

	@Override
	public void dispose() {
		ISelectionService s = getSite().getWorkbenchWindow().getSelectionService();
		s.removeSelectionListener(this);
		super.dispose();
	}

	@Override
	public void setFocus() {
	}

	protected void addRelatedObject(final IPerson person) {
		Display.getDefault().asyncExec(new Runnable() {

			public void run() {
				PersonHyperlink hyperlink = new PersonHyperlink(relatedObjectsComposite, SWT.NONE);
				hyperlink.setPerson(person);
				linkGroup.add(hyperlink.getImageHyperlink());
				relatedObjectsComposite.layout(new Control[] { hyperlink });
			}

		});
	}

	protected void addRelatedObject(final URL url) {
		Display.getDefault().asyncExec(new Runnable() {

			public void run() {
				ImageHyperlink hyperlink = new ImageHyperlink(relatedObjectsComposite, SWT.NONE);
				hyperlink.setImage(Activator.getImageDescriptor("icons/page_white_world.png").createImage());
				hyperlink.setText("Web Page");
				hyperlink.addHyperlinkListener(new HyperlinkAdapter() {

					@Override
					public void linkActivated(HyperlinkEvent event) {
						IWorkbench workbench = PlatformUI.getWorkbench();
						IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
						IWorkbenchPage workbenchPage = window.getActivePage();
						try {
							workbenchPage.openEditor(new BrowserEditorInput(url.toString()), BrowserEditor.ID, true, IWorkbenchPage.MATCH_INPUT | IWorkbenchPage.MATCH_ID);
						} catch (PartInitException e) {
							MessageDialog.openError(window.getShell(), "Error", "Error opening browser: " + e.getMessage());
						}
					}
				
				});
				linkGroup.add(hyperlink);
				relatedObjectsComposite.layout(new Control[] { hyperlink });
			}

		});
	}

	protected void clearRelatedObjects() {
		Display.getDefault().asyncExec(new Runnable() {

			public void run() {
				Control[] children = relatedObjectsComposite.getChildren();
				for (int i = children.length - 1; i >= 0; i--)
					children[i].dispose();
			}

		});
	}

	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if (selection instanceof IStructuredSelection) {
			Iterator<?> iter = ((IStructuredSelection) selection).iterator();
			while (iter.hasNext()) {
				Object object = iter.next();
				if (object instanceof URI) {
					URI uri = (URI) object;

					if (collector != null)
						collector.cancel();
					collector = null;

					clearRelatedObjects();

					collector = new Collector<Object>();
					collector.addListener(new ICollectorListener<Object>() {

						public void elementAdded(Collector<Object> collector, Object element) {
							if (collector != RelatedItemsView.this.collector)
								return;
							
							IPerson person = getPerson(element);
							if (person != null)
								addRelatedObject(person);
							else if (element instanceof URL)
								addRelatedObject((URL) element);
						}

						public void providerStatusChanged(final Collector<Object> collector, String providerName, boolean active) {
						}

					});

					DataBroker.getDefault().getRelatedObjects(uri.toString(), collector);
					
					return;
				} else if (object instanceof IPerson) {
					IPerson person = (IPerson) object;

					if (collector != null)
						collector.cancel();
					collector = null;

					clearRelatedObjects();

					collector = new Collector<Object>();
					collector.addListener(new ICollectorListener<Object>() {

						public void elementAdded(Collector<Object> collector, Object element) {
							if (collector != RelatedItemsView.this.collector)
								return;
							
							IPerson person = getPerson(element);
							if (person != null)
								addRelatedObject(person);
							else if (element instanceof URL)
								addRelatedObject((URL) element);
						}

						public void providerStatusChanged(final Collector<Object> collector, String providerName, boolean active) {
						}

					});

					DataBroker.getDefault().getRelatedObjects(person, collector);
					
					return;
				}
			}
		}

		if (collector != null)
			collector.cancel();
		collector = null;

		clearRelatedObjects();
	}

	protected static IPerson getPerson(Object element) {
		// First, if the object is an ImageProvider, use it.
		if (IPerson.class.isInstance(element))
			return (IPerson) element;

		// Second, if the object is adaptable, ask it to get an adapter.
		IPerson person = null;
		if (element instanceof IAdaptable)
			person = (IPerson) ((IAdaptable) element).getAdapter(IPerson.class);
		
		// If we haven't found an adapter yet, try asking the AdapterManager.
		if (person == null)
			person = (IPerson) Platform.getAdapterManager().loadAdapter(element, IPerson.class.getName());

		return person;
	}

}
